// linux_StackWalker.h

#ifndef _linux_StackWalker_h_
#define _linux_StackWalker_h_

#if defined(_MSC_VER) && (_MSC_VER > 1000)
	#pragma once
#endif

#include <execinfo.h>
#include <cxxabi.h>

class linux_StackWalker
{
	struct StrPair
	{
		const char* p_;
		int len_;
		StrPair() : p_(NULL), len_(0) {}
		StrPair(const char* p, int len) : p_(p), len_(len) {}
	};

public:
	virtual ~linux_StackWalker() {}
	void ShowCallstack()
	{
		void* array[10];
		int size = backtrace(array, 10);
		char** strs = backtrace_symbols(array, size);
		for(int i=0; i<size; i++)
		{
			if(strstr(strs[i], "linux_StackWalker"))
				continue;

			int status = 0;
			char name[512];
			char func_name[512];
			char func_offset[16];
			char addr[16];
            memset(name, 0, sizeof(name));
            
			const char* sep1 = strs[i];
			const char* sep2 = strchr(sep1, '(');
            if(sep2)
			{
			//	StrPair mod_path(sep1, sep2-sep1);
				sep1 = sep2 + 1;

				sep2 = strchr(sep1, '+');
				strncpy(func_name, sep1, sep2-sep1);
				func_name[sep2-sep1] = 0;
				sep1 = sep2 + 1;

				sep2 = strchr(sep1+1, ')');
				strncpy(func_offset, sep1, sep2-sep1);
				func_offset[sep2-sep1] = 0;
				sep1 = sep2 + 1;

				sep2 = strchr(sep1+1, '[');
				sep1 = sep2 + 1;

				sep2 = strchr(sep1+1, ']');
				strncpy(addr, sep1, sep2-sep1);
				addr[sep2-sep1] = 0;
				sep1 = sep2 + 1;

				size_t si = sizeof(name)/sizeof(name[0]);
				__cxxabiv1::__cxa_demangle(func_name, name, &si, &status);
			}
			char buf[1024];
			if(0 == status)
				sprintf(buf, "%s + %s, %s", name, func_offset, addr);
			else
				sprintf(buf, "%s() + %s, %s", func_name, func_offset, addr);

			this->OnOutput(buf);
		}
		::free(strs);
	}

protected:
	virtual void OnOutput(const char* szText)
		{	printf("%s", (szText?szText:""));	}
};

#endif	// #ifndef _linux_StackWalker_h_
